/**
  ******************************************************************************
  * @file    sensor_service.c
  * @author  MCD Application Team
  * @version V1.0.0
  * @date    04-July-2014
  * @brief   Add a sample service using a vendor specific profile.
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; COPYRIGHT(c) 2014 STMicroelectronics</center></h2>
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */
#include "sensor_service.h"
#include "stm32_bluenrg_ble.h"
#include "app.h"
#include "app_ip.h"
#include "app_ota.h"
#include "error.h"
#include "task.h"
#include "stm32l052_lp_mode.h"
#include "app_ble_irq_handle.h"
#include "eeprom.h"
#include "wdg.h"
#include "tftp_server.h"
/* Private variables ---------------------------------------------------------*/
extern uint32_t task_flag;
extern volatile uint8_t connect_state;
extern volatile uint8_t adv_state;
extern volatile uint8_t hfc_state;
const char *name = "Blue IP";
uint8_t bdaddr[6] = {0x12, 0x34, 0x00, 0xE1, 0x80, 0x07};
extern SPI_HandleTypeDef SpiHandle;
volatile uint16_t connection_handle = 0;
volatile uint8_t ble_init_flag = 0;
/*OTA*/
/*IP*/
uint16_t ipRxTxServHandle = 0, ipRxTxWriteCharHandle = 0, ipRxTxNotifyCharHandle = 0;

uint16_t service_handle, dev_name_char_handle, appearance_char_handle;
/*config infomation*/
ble_eeprom_data_t ble_param_data;

/* Private functions ---------------------------------------------------------*/
static void bluenrg_set_address(uint8_t* bdaddr);
static void bluenrg_gatt_gap_init(void);
#ifdef UNIQUE_ADDRESS
static void bluenrg_get_unique_adv_address(void);
#endif
static void get_eeprom_ble_address(void);
/**
 * @}
 */

/** @defgroup SENSOR_SERVICE_Private_Macros
 * @{
 */
/* Private macros ------------------------------------------------------------*/

/* Store Value into a buffer in Little Endian Format */
#define STORE_LE_16(buf, val)    ( ((buf)[0] =  (uint8_t) (val)    ) , \
                                   ((buf)[1] =  (uint8_t) (val>>8) ) )

void bluenrg_get_config_info(ble_eeprom_data_t* param_data)
{
    param_data->adv_interval = eeprom_read_half_word(EEPROM_BLUENRG_ADV_INTERVAL_ADDR);
    param_data->adv_widnow = eeprom_read_half_word(EEPROM_BLUENRG_ADV_INTERVAL_ADDR + 2);
    param_data->adv_period = eeprom_read_word(EEPROM_BLUENRG_ADV_INTERVAL_ADDR + 4);
}

void ble_begin(void)
{
    bluenrg_io_init();
    bluenrg_start_work();
    Disable_SPI_IRQ();
}

void ble_standby(void)
{   
    aci_hal_device_standby();
}

tBleStatus bluenrg_init(uint8_t* bdaddr)
{
    bluenrg_set_address(bdaddr);
    bluenrg_gatt_gap_init();

#ifdef APP_IP
    if(bluenrg_add_ip_rx_tx_service() != BLE_STATUS_SUCCESS)
        return BLE_STATUS_ERROR;     
#endif 
    aci_hal_set_tx_power_level(1,7);
    
    return BLE_STATUS_SUCCESS;
}

static void bluenrg_set_address(uint8_t* bdaddr)
{
    uint8_t write_config_data_mode = 0x02;
    if(aci_hal_write_config_data(0x2D, 0x01, &write_config_data_mode) != BLE_STATUS_SUCCESS)
        while(1);
   
    if(aci_hal_write_config_data(CONFIG_DATA_PUBADDR_OFFSET, CONFIG_DATA_PUBADDR_LEN, bdaddr) != BLE_STATUS_SUCCESS)
        while(1);
}

static void bluenrg_gatt_gap_init(void)
{
    if(aci_gatt_init() != BLE_STATUS_SUCCESS)
        while(1);
    if(aci_gap_init_IDB05A1(GAP_PERIPHERAL_ROLE_IDB05A1, 0, 0x07, &service_handle, &dev_name_char_handle, &appearance_char_handle) != BLE_STATUS_SUCCESS)
        while(1);
    if(aci_gatt_update_char_value(service_handle, dev_name_char_handle, 0, strlen(name), (uint8_t *)name) != BLE_STATUS_SUCCESS)
        while(1);
}

void setConnectable(void)
{  
  
  const char local_name[] = {AD_TYPE_COMPLETE_LOCAL_NAME,'W','i','i','H','e','y','D','1'};
  
  ble_init_flag = 1;
  /* disable scan response */
  //hci_le_set_scan_resp_data(0,NULL);
  if(task_flag == FALSE)
      ble_param_data.adv_interval = 500;
  
  aci_gap_set_discoverable(ADV_IND, ble_param_data.adv_interval,ble_param_data.adv_interval, PUBLIC_ADDR, NO_WHITE_LIST_USE,
                                 sizeof(local_name), local_name, 0, NULL, 0, 0);

                                
}

#ifdef MANUFACTURE_ADV
tBleStatus bluenrg_delete_adv_type(uint8_t data)
{
    if(aci_gap_delete_ad_type(data) != BLE_STATUS_SUCCESS)
         return BLE_STATUS_ERROR;
    
    return BLE_STATUS_SUCCESS;
         
}
#endif

void bluenrg_stop_adv(void)
{
    
    aci_gap_set_non_discoverable();
        
}

#ifdef MANUFACTURE_ADV
tBleStatus bluenrg_adv_manufacture_data(uint8_t* data, uint8_t len)
{
     if(aci_gap_set_discoverable(ADV_IND, 1000, 1000, PUBLIC_ADDR, NO_WHITE_LIST_USE,
                                 len-1, (const char*)(data+1), 0, NULL, 0, 0) != BLE_STATUS_SUCCESS)
      while(1);
                       
    if(bluenrg_delete_adv_type(AD_TYPE_TX_POWER_LEVEL) != BLE_STATUS_SUCCESS)
      while(1);
    
    return BLE_STATUS_SUCCESS;
}

void bluenrg_update_adv(void* data)
{
    if(aci_gap_update_adv_data(0x04, data) != BLE_STATUS_SUCCESS)
        while(1);
}
#endif

void bluenrg_io_init(void)
{
     /* Initialize the BlueNRG SPI driver */
    BNRG_SPI_Init();
    /* Initialize the BlueNRG HCI */
    HCI_Init();
}


/*ip***********************************************************************************************/

tBleStatus bluenrg_add_ip_rx_tx_service(void)
{
    uint8_t ret;
    uint8_t uuid_1[2] = {0x0c,0xff};
    uint8_t uuid_2[2] = {0x0d,0xff};
    uint8_t uuid_3[2] = {0x0e,0xff};

    ret = aci_gatt_add_serv(UUID_TYPE_16,  uuid_1, PRIMARY_SERVICE, 10, &ipRxTxServHandle); /* TBR: original = 41 moved to 10 */
    if (ret != BLE_STATUS_SUCCESS)
        return BLE_STATUS_ERROR;
 
    ret =  aci_gatt_add_char(ipRxTxServHandle, UUID_TYPE_16, uuid_2, 20, CHAR_PROP_WRITE_WITHOUT_RESP, ATTR_PERMISSION_NONE, GATT_NOTIFY_ATTRIBUTE_WRITE,
                             16, 1, &ipRxTxWriteCharHandle);
    if (ret != BLE_STATUS_SUCCESS) 
        return BLE_STATUS_ERROR;
    
    ret =  aci_gatt_add_char(ipRxTxServHandle, UUID_TYPE_16, uuid_3, 20, CHAR_PROP_NOTIFY, ATTR_PERMISSION_NONE, GATT_DONT_NOTIFY_EVENTS,
                             16, 1, &ipRxTxNotifyCharHandle);
    if (ret != BLE_STATUS_SUCCESS) 
        return BLE_STATUS_ERROR;
    
    return BLE_STATUS_SUCCESS;
}

void bluenrg_start_work(void)
{
    /* Reset BlueNRG hardware */
    BlueNRG_RST();
    /*set unique adv address*/
    get_eeprom_ble_address();
    /*init bluenrg*/
    bluenrg_init(bdaddr); 
    HCI_Process();
    
}

/**
 * @brief  This function is called when there is a LE Connection Complete event.
 * @param  uint8_t Address of peer device
 * @param  uint16_t Connection handle
 * @retval None
 */
void GAP_ConnectionComplete_CB(uint8_t addr[6], uint16_t handle)
{  
 
  connect_state = TRUE;
  connection_handle = handle;

#if PRINTF_DEBUG  
  PRINTF("Connected to device:");
  for(int i = 5; i > 0; i--){
    PRINTF("%02X-", addr[i]);
  }
  PRINTF("%02X\n", addr[0]);
#endif
}

/**
 * @brief  This function is called when the peer device gets disconnected.
 * @param  None 
 * @retval None
 */
void GAP_DisconnectionComplete_CB(void)
{
  connect_state = FALSE;
   adv_state = FALSE;
#if PRINTF_DEBUG
  PRINTF("Disconnected\n");
#endif
}

/**
 * @brief  Read request callback.
 * @param  uint16_t Handle of the attribute
 * @retval None
 */
void Read_Request_CB(uint16_t handle)
{  

  if(connection_handle != 0)
    aci_gatt_allow_read(connection_handle);
}

/**
 * @brief  Callback processing the ACI events.
 * @note   Inside this function each event must be identified and correctly
 *         parsed.
 * @param  void* Pointer to the ACI packet
 * @retval None
 */
void HCI_Event_CB(void *pckt)
{
  hci_uart_pckt *hci_pckt = pckt;
  /* obtain event packet */
  hci_event_pckt *event_pckt = (hci_event_pckt*)hci_pckt->data;
  
  if(hci_pckt->type != HCI_EVENT_PKT)
    return;
  
  switch(event_pckt->evt){
    
  case EVT_DISCONN_COMPLETE:
    {
      GAP_DisconnectionComplete_CB();
    }
    break;
  case EVT_CMD_COMPLETE:
    {
      evt_cmd_complete *evt = (void *)event_pckt->data;
      if(evt->opcode == OPCODE_UPDATE_CHAR_VALUE)
      {
           hfc_state = TRUE;
           ble_update_char_value_callback(event_pckt->data[3]);
      }
      if(evt->opcode == OPCODE_SET_DISCOVERABLE)
          hfc_state = TRUE;
     
      if(evt->opcode == OPCODE_SET_NON_DISCOVERABLE)
          hfc_state = TRUE;
      
      if(evt->opcode == OPCODE_BLE_STANDBY)
       hfc_state = TRUE;
    }
    break; 
  case EVT_LE_META_EVENT:
    {
      evt_le_meta_event *evt = (void *)event_pckt->data;
      
      switch(evt->subevent){
      case EVT_LE_CONN_COMPLETE:
        {
          evt_le_connection_complete *cc = (void *)evt->data;
          GAP_ConnectionComplete_CB(cc->peer_bdaddr, cc->handle);
        }
        break;
      }
    }
    break;
    
  case EVT_VENDOR:
    {
      evt_blue_aci *blue_evt = (void*)event_pckt->data;
      switch(blue_evt->ecode){

      case EVT_BLUE_GATT_ATTRIBUTE_MODIFIED:         
        {
          /* this callback is invoked when a GATT attribute is modified
          extract callback data and pass to suitable handler function */
            evt_gatt_attr_modified_IDB05A1 *evt = (evt_gatt_attr_modified_IDB05A1*)blue_evt->data;
            Attribute_Modified_CB(evt->attr_handle, evt->data_length, evt->att_data);                           
        }
        break; 

      case EVT_BLUE_GATT_READ_PERMIT_REQ:
        {
          evt_gatt_read_permit_req *pr = (void*)blue_evt->data;                    
          Read_Request_CB(pr->attr_handle);                    
        }
        break;
      }
    }
    break;
  }    
}

/**
 * @brief  This function is called attribute value corresponding to 
 *         ledButtonCharHandle characteristic gets modified.
 * @param  Handle of the attribute
 * @param  Size of the modified attribute data
 * @param  Pointer to the modified attribute data
 * @retval None
 */
void Attribute_Modified_CB(uint16_t handle, uint8_t data_length, uint8_t *att_data)
{

 /*ip rx*/
 if(handle == ipRxTxWriteCharHandle + 1){
     app_ip_rx_receive_data(att_data, data_length);
 }
      
}

void ble_update_char_value_callback(uint8_t status)
{
    
    app_update_char_value_cb(status);
}


/*get eeprom ble address*/
static void get_eeprom_ble_address(void)
{
    uint8_t i = 0;
 
    for(i = 0; i < 6; i++)
        bdaddr[i] = eeprom_read_byte(EEPROM_BLE_ADDRESS_VALUE + i);
}

/*ble address set***********************************************************************************/
bool _ble_address_cmd_open(char* name, uint8_t mode)
{
    if (mode != TFTP_WRQ) return false;
    
    if (0 == strcmp(name, "ble.address")) {
        return true;
    } else {
        return false;
    }
}

uint16_t (_ble_address_cmd_read)(uint8_t blk, uint8_t* buffer)
{
    return 0;
}

void (_ble_address_cmd_write)(uint8_t blk, uint8_t* buffer, uint16_t len)
{
     uint8_t i ;
     uint32_t* p = (uint32_t*)buffer;
 
     eeprom_erase(2, EEPROM_BLE_ADDRESS_VALUE);
 
     HAL_FLASHEx_DATAEEPROM_Unlock();
    /*clear  write proctect flag*/
    __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_WRPERR);
 
    for(i = 0; i < 2; i++)
        HAL_FLASHEx_DATAEEPROM_Program(FLASH_TYPEPROGRAM_WORD, EEPROM_BLE_ADDRESS_VALUE, *(p + i));
 
    HAL_FLASHEx_DATAEEPROM_Lock();
}

void (_ble_address_cmd_close)(void)
{

}

const tftp_server_plugin_t tftp_server_plugin_ble_address_cmd = {
    _ble_address_cmd_open,
    _ble_address_cmd_read,
    _ble_address_cmd_write,
    _ble_address_cmd_close,
};

/**
 * @}
 */
#ifdef UNIQUE_ADDRESS
static void bluenrg_get_unique_adv_address(void)
{
    int i;
    /* Generate 48bit bdAddr from Unique device ID register (96 bits).
     * NOTE: Might be not unique! So change to other method if need.
     */

#define CHIP_UNIQUE_ID_REG	((const __IO uint8_t *)0x1FF80050)	// move to a proper place?
 
    memcpy(bdaddr, (void*)CHIP_UNIQUE_ID_REG, 6);

    for (i=0; i<6; i++) {
       bdaddr[i] += CHIP_UNIQUE_ID_REG[6 + i];
       bdaddr[i] += CHIP_UNIQUE_ID_REG[10 + i];
    }
}
#endif

/**
 * @}
 */

/**
 * @}
 */

 /**
 * @}
 */
 
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
